package cn.com.sbell.vss.auth.radius;

import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
import net.sourceforge.jradiusclient.RadiusAttribute;
import net.sourceforge.jradiusclient.RadiusAttributeValues;
import net.sourceforge.jradiusclient.RadiusPacket;
import net.sourceforge.jradiusclient.attributes.VendorSpecificAttribute;
import net.sourceforge.jradiusclient.packets.PapAccessRequest;
import cn.com.sbell.vss.Util;
import cn.com.sbell.vss.VissSession;
import cn.com.sbell.vss.VssConstants;
import cn.com.sbell.vss.VssException;
import cn.com.sbell.vss.csg.vap.util.CrossDomainCredential;
import cn.com.sbell.vss.auth.radius.bean.ServerAddress;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class RadiusAuthenticate {
	private static Log logger=LogFactory.getLog(RadiusAuthenticate.class);
	public static final int VISS_NAS_TYPE = 5;

	public static final int VISS_VS_IP_ADDRESS = 1;//从csg1.7-phase3开始改为用deviceId唯一标识一个VS,而不用VSIP
	
	public static final int VISS_FRONT_ID = 29;//从csg1.7-phase3开始改为用deviceId唯一标识一个VS,而不用VSIP

	public static final int VISS_VS_USERAME = 3;

	public static final int VISS_VS_PASSWORD = 4;
	
	public static final int AUTH_TYPE=31;
	
	public static final int VISS_FRONT_TYPE=15;// distinguish ah and vs
	
	public static void authenticate(String username, String password, String vsIp,
			int vsPort, String vsDeviceId, VissSession session,
			String localIp,int nasType ,VssRadiusClient vssRadiusClient,
			CrossDomainCredential cdc,boolean AuthFlag_isDest
			,byte front_type) throws VssException {
		try {
			logger.debug("username:"+username
					+",password:"+password
					+",vsIp:"+vsIp
					+",vsPort:"+vsPort
					+",vsDeviceId:"+vsDeviceId
					+",localIp:"+localIp
					+",nasType:"+nasType
					+",AuthFlag_isDest:"+AuthFlag_isDest
					+",front_Type:"+front_type);
			PapAccessRequest accessRequest = new PapAccessRequest(username,
					password);
			accessRequest.setAttribute(new RadiusAttribute(
					RadiusAttributeValues.NAS_IP_ADDRESS, getIpBytes(localIp,logger)));
			accessRequest.setAttribute(new VendorSpecificAttribute(
					VISS_NAS_TYPE, new byte[] {
							(byte) ((nasType >>> 24) & 0xFF),
							(byte) ((nasType >>> 16) & 0xFF),
							(byte) ((nasType >>> 8) & 0xFF),
							(byte) ((nasType >>> 0) & 0xFF) }));
			if (vsDeviceId != null) {
				accessRequest.setAttribute(new VendorSpecificAttribute(
						VISS_FRONT_ID, vsDeviceId.getBytes()));
			}
			if(AuthFlag_isDest)
			{
				accessRequest.setAttribute(new VendorSpecificAttribute(
						AUTH_TYPE, new byte[]{1}));
			}else
			{
				accessRequest.setAttribute(new VendorSpecificAttribute(
						AUTH_TYPE, new byte[]{0}));
			}
			accessRequest.setAttribute(new VendorSpecificAttribute(
					VISS_FRONT_TYPE, new byte[]{front_type}));
			RadiusPacket accessResponse = vssRadiusClient
					.authenticate(accessRequest);
			if (accessResponse == null) {
				throw new VssException(VssConstants.CODE_AUTHENTICATION_FAILED);
			}
			switch (accessResponse.getPacketType()) {
			case RadiusPacket.ACCESS_ACCEPT:
				if(logger.isDebugEnabled()){
				logger.debug("User " + username + " authenticated");
				}
				if (vsDeviceId != null) {
					RadiusAttribute[] ras = accessResponse.getAttributes(26);
					VendorSpecificAttribute uname = null;
					VendorSpecificAttribute pwd = null;
					for (int i = 0; i < ras.length; i++) {
						if (((VendorSpecificAttribute) ras[i]).getVendorType() == 3) {
							uname = (VendorSpecificAttribute) ras[i];
						} else if (((VendorSpecificAttribute) ras[i])
								.getVendorType() == 4) {
							pwd = (VendorSpecificAttribute) ras[i];
						}
					}
					if (uname != null && pwd != null) {
						if(session!=null){
						session.setCurrentVsIp(vsIp);
						session.setCurrentVsPort(vsPort);
						session.setCurrentVsDeviceId(vsDeviceId);
						session.setCurrentVsLoginUsername(new String(uname
								.getVendorValue()));
						session.setCurrentVsLoginPassword(new String(pwd
								.getVendorValue()));
						}
						if(cdc!=null)
						{
							cdc.setNextDomainPassWord(new String(pwd.getVendorValue()));
							cdc.setNextDomainUserName(new String(uname.getVendorValue()));
						}
					}
				}
				// sessionHolder.setSessionTimeout(accessRequest.getAttribute(
				// RadiusAttributeValues.SESSION_TIMEOUT).getIntValue());
				break;
			case RadiusPacket.ACCESS_REJECT:
				if(logger.isDebugEnabled()){
				logger.debug("User " + username + " NOT authenticated");
				}
				RadiusAttribute attr = accessResponse
						.getAttribute(RadiusAttributeValues.REPLY_MESSAGE);
				throw new VssException(new String(attr.getValue()));
			case RadiusPacket.ACCESS_CHALLENGE:
				String reply = new String(accessResponse.getAttribute(
						RadiusAttributeValues.REPLY_MESSAGE).getValue());
				if(logger.isDebugEnabled()){
				logger.debug("User " + username + " Challenged with " + reply);
				}
				throw new VssException(VssConstants.CODE_AUTHENTICATION_FAILED);
			default:
				if(logger.isDebugEnabled()){
				logger.debug("Whoa, what kind of RadiusPacket is this "
						+ accessResponse.getPacketType());
				}
				throw new VssException(VssConstants.CODE_AUTHENTICATION_FAILED);
			}
		} catch (VssException e) {
			throw e;
		} catch (Throwable e) {
			if(logger.isWarnEnabled()){
			logger.warn("Authenticate Exception", e);
			}
			throw new VssException(VssConstants.CODE_AUTHENTICATION_FAILED);
		}
	}
	public static byte[] getIpBytes(String host,Log log) {
		try {
			InetAddress ad = InetAddress.getByName(host);
			return ad.getAddress();
		} catch (UnknownHostException ex) {
			if(log.isWarnEnabled()){
			log.warn("UnknownHostException", ex);
			}
			throw new VssException(VssConstants.CODE_PARAMETER_ERROR);
		}
	}
	public static ServerAddress getServerAddress(HttpServletRequest request)
	{
		String serverIp=null;
		int serverPort=0;
		String serverId=null;
		String frontType=(String)request.getAttribute(VssConstants.KEY_FRONT_TYPE);
		byte front_type=0;
		if(VssConstants.FRONT_TYPE_VS.equalsIgnoreCase(frontType))
		{
			front_type=0;
			serverIp="0.0.0.0";
			serverPort=0;
			serverId=request.getParameter("vsDeviceId");
		}else if(VssConstants.FRONT_TYPE_IPCAM.equals(frontType)){
			front_type=1;
			serverIp="0.0.0.0";
			serverPort=0;
			serverId=request.getParameter("vsDeviceId");
		
		}else if(VssConstants.FRONT_TYPE_AH.equalsIgnoreCase(frontType))
		{

			front_type=2;
			serverIp=request.getParameter("serverIp");
			String serverPort_=request.getParameter("serverPort");
			
			if(Util.strIsNull(serverIp)&&Util.strIsNull(serverPort_))
			{
				serverIp=request.getRemoteHost();
				serverPort=request.getRemotePort();
				
			}else
			{
				serverPort=Integer.parseInt(serverPort_);
			}
			
			serverId=request.getParameter("deviceId");
			
		}
		return new ServerAddress(serverIp,serverPort,serverId,front_type);
	}
}
